/*
 * @Description  : Watchdog service task implementation
 * @Version      : 0.1
 * @Company      : V-Think Development Team
 * @Author       : GitHub Copilot
 * @Date         : 2025-09-29 15:30:00
 */
#include <appWatchdog.h>

static TickType_t heartbeatTicks[WATCHDOG_SRC_COUNT] = {0};
static bool heartbeatMissing[WATCHDOG_SRC_COUNT] = {false};
static SemaphoreHandle_t heartbeatMutex = nullptr;
static const char *const watchdogSourceNames[WATCHDOG_SRC_COUNT] ={ "periph", "modbus", "phase" };

void watchdogReport(WatchdogSource_t source)
{
    if ((source >= WATCHDOG_SRC_COUNT) || (heartbeatMutex == nullptr))
    {
        return;
    }

    if (xSemaphoreTake(heartbeatMutex, pdMS_TO_TICKS(5)) == pdTRUE)
    {
        heartbeatTicks[source] = xTaskGetTickCount();
        xSemaphoreGive(heartbeatMutex);
    }
}

osThreadId watchdogTaskHandle;
void watchdogTask(void *pvParameters)
{
    UNUSED(pvParameters);

    if (heartbeatMutex == nullptr)
    {
        heartbeatMutex = xSemaphoreCreateMutex();
    }

    TickType_t now = xTaskGetTickCount();
    for (uint8_t i = 0; i < WATCHDOG_SRC_COUNT; ++i)
    {
        heartbeatTicks[i] = now;
    }

    const TickType_t refreshDelay = pdMS_TO_TICKS(WATCHDOG_REFRESH_MS);
    const TickType_t heartbeatTtl = pdMS_TO_TICKS(WATCHDOG_HEARTBEAT_TTL_MS);

    xLog.info("Watchdog task started, refresh every %lus, heartbeat TTL %lus\r\n",
              static_cast<unsigned long>(WATCHDOG_REFRESH_MS / 1000U),
              static_cast<unsigned long>(WATCHDOG_HEARTBEAT_TTL_MS / 1000U));

    for (;;)
    {
        bool allAlive = true;
        bool mutexLocked = false;
        now = xTaskGetTickCount();

        if (heartbeatMutex != nullptr)
        {
            if (xSemaphoreTake(heartbeatMutex, pdMS_TO_TICKS(5)) == pdTRUE)
            {
                mutexLocked = true;
                for (uint8_t i = 0; i < WATCHDOG_SRC_COUNT; ++i)
                {
                    bool missingNow = ((now - heartbeatTicks[i]) > heartbeatTtl);
                    if (missingNow)
                    {
                        allAlive = false;
                        if (!heartbeatMissing[i])
                        {
                            xLog.error("Watchdog missed [%s] heartbeat\r\n", watchdogSourceNames[i]);
                        }
                    }
                    else if (heartbeatMissing[i])
                    {
                        xLog.info("Watchdog heartbeat recovered [%s]\r\n", watchdogSourceNames[i]);
                    }
                    heartbeatMissing[i] = missingNow;
                }
                xSemaphoreGive(heartbeatMutex);
            }
            else
            {
                allAlive = false;
                xLog.error("Watchdog mutex timeout, skip refresh\r\n");
            }
        }
        else
        {
            allAlive = false;
            xLog.error("Watchdog mutex not created, skip refresh\r\n");
        }

        if (allAlive && IWatchdog.isEnabled())
        {
            IWatchdog.reload();
            xLog.trace("Watchdog fed successfully\r\n");
        }
        else if (!allAlive && mutexLocked)
        {
            // missing sources already logged during evaluation
        }

        vTaskDelay(refreshDelay);
    }
}
